package com.rgbgame.game;

/**
 * A com.rgbgame.game.Spring is an abstract amount of force exerted between two Particles.
 * @author Will
 * @date Mar 4, 2008 - 1:52:16 PM
 */
public final class Spring {

    private Particle particleA;
    private Particle particleB;
    private float restLength;
    private float forceConstant;
    private float friction;

    public Spring(Particle _pA, Particle _pB, float _restLength,
                  float _forceConstant, float _friction) {
        // debugCounter++;
        particleA = _pA;
        particleB = _pB;
        restLength = _restLength;
        forceConstant = _forceConstant;
        friction = _friction;
    }

    public Spring(Particle _pA, Particle _pB, float _forceConstant,
                  float _friction) {
        this(_pA, _pB, _pA.distanceTo(_pB), _forceConstant, _friction);
    }

    public Spring(Particle _pA, Particle _pB, float _forceConstant) {
        this(_pA, _pB, _pA.distanceTo(_pB), _forceConstant, Const.defaultFriction);
    }

    public Spring(Particle _pA, Particle _pB) {
        this(_pA, _pB, Const.defaultForceConstant);
    }

    public void setRestLength(float newLength) {
        restLength = newLength;
    }

    public float getRestLength() {
        return restLength;
    }

    public void setForceConstant(float newConstant) {
        forceConstant = newConstant;
    }

    public float getForceConstant() {
        return forceConstant;
    }

    public void applyForce() {
        // 225x per frame (with 5 steps per frame)
        particleA.setVel(); // for Verlet scheme, need to compute velocities
        // before using them
        particleB.setVel();
        float springForce;
        Vector3d springf;
        float separation = particleA.distanceTo(particleB);
        if (separation > 0.0001f) {
            springForce = -forceConstant * (separation - restLength);
            springf = particleA.position.minus(particleB.position);
            springf.normalize();
            Vector3d relVel = particleA.velocity.minus(particleB.velocity);
            float projection = -friction * relVel.dot(springf);
            springForce += projection;
            springf.multiply(springForce);
            particleA.forceAdd(springf);
            particleB.forceSubtract(springf);
        }
    }

}
